<?php
/**
 * 
 * @author Paolo Bertuzzo
 *
 */
namespace Catalog\Service;

use Catalog\Data\BasketDao;
use Utilities\Session\SessionFacade;
use Catalog\Data\BasketItemDao;
use Catalog\Data\LocalizedProductTextDao;
use Catalog\Data\ProductPriceDao;
use Catalog\Data\AttributeValuePriceDao;
use Catalog\Data\AttributeDao;
use Zend\Json\Encoder;
use Catalog\Data\ProductImageDao;

class BasketService
{
    
    /**
     * 
     */
    protected $basketDao;
    
    /**
     * 
     */
    protected $basketItemDao;
    
    /**
     * 
     */
    protected $localizedProductTextDao;
    
    /**
     * 
     */
    protected $productPriceDao;

    /**
     *
     */
    protected $productImageDao;
    
    /**
     * 
     */
    protected $attributeValuePriceDao;
    
    /**
     * 
     */
    protected $attributeDao;
    
    /**
     * 
     * @param BasketDao $basketDao
     * @param BasketItemDao $basketItemDao
     * @param LocalizedProductTextDao $localizedProductTextDao
     * @param ProductPriceDao $productPriceDao
     * @param ProductImageDao $productImageDao
     * @param AttributeValuePriceDao $attributeValuePriceDao
     * @param AttributeDao $attributeDao
     */
    public function __construct(BasketDao $basketDao, BasketItemDao $basketItemDao, LocalizedProductTextDao $localizedProductTextDao,
        ProductPriceDao $productPriceDao, ProductImageDao $productImageDao, AttributeValuePriceDao $attributeValuePriceDao, AttributeDao $attributeDao)
    {
        $this->basketDao = $basketDao;
        $this->basketItemDao = $basketItemDao;
        $this->localizedProductTextDao = $localizedProductTextDao;
        $this->productPriceDao = $productPriceDao;
        $this->productImageDao = $productImageDao;
        $this->attributeValuePriceDao = $attributeValuePriceDao;
        $this->attributeDao = $attributeDao;
    }
    
    /**
     */
    public function get()
    {
        $basket = $this->getBasket();
        
    	return array(
    		'basket' => $basket,
    	    'items' => $this->basketItemDao->get($basket->getId())
    	);
    }
    
    /**
     * 
     * @param integer $productId
     * @param integer $quantity
     * @param array $attributes
     */
    public function addItem($productId, $quantity, $attributes)
    {
        $sessionFacade = new SessionFacade();
        
        // Get the basket
        $basket = $this->getBasket();
        
        // Add the item to the basket. Attributes are saved as JSON
        $price = $this->getPrice($productId, $attributes);
        $vat = $this->getVat($productId);
        $image = $this->productImageDao->getByType($productId, $sessionFacade->getStore()->getLanguage(), 'basket');
        
        $this->basketItemDao->insert($basket->getId(), $productId, $quantity, $price, $vat,
            $this->getLocalizedProductName($productId), $this->getAttributesMap($attributes), $image[0]->getUrl());
        
        // Update basket totals
        $this->updateTotals($basket->getId());
    }

    /**
     * 
     * @param integer $itemId
     */
    public function deleteItem($basketItemId) 
    {
        $sessionFacade = new SessionFacade();
        
        // Check if item belongs to the session basket
        $basket = $this->getBasket();
        $basketItem = $this->basketItemDao->getById($basketItemId);

        // If item was not found, return immediately
        if (is_null($basketItem) || (!is_null($basketItem) && $basketItem->getBasketId() != $basket->getId()))
            return;
        
        // Delete the item
        $this->basketItemDao->delete($basketItemId);
        
        // Update basket totals
        $this->updateTotals($basket->getId());
    }
    
    /**
     * 
     * @param integer $basketId
     */
    private function updateTotals($basketId) 
    {
        // Update the basket
        $sumOfQuantity = $this->basketItemDao->getQuantitySum($basketId);
        $sumOfPrice = $this->basketItemDao->getPriceSum($basketId);
        
        $this->basketDao->update($basketId, is_null($sumOfQuantity) ? 0 : $sumOfQuantity, 
            is_null($sumOfPrice) ? 0 : $sumOfPrice);
    }
    
    /**
     * 
     * @param array $attributes
     * @return array
     */
    private function getAttributesMap($attributes) 
    {
        if (count($attributes) == 0)
            return null;

        $sessionFacade = new SessionFacade();
        
        $attributeValueIds = array();
        $localizedAttributes = array();
        
        foreach ($attributes as $attribute)
        	array_push($attributeValueIds, $attribute['value']);
        
    	$localizedAttributesValuesAndNames = $this->attributeDao->getLocalizedAttributes($attributeValueIds, $sessionFacade->getStore()->getLanguage());

	    foreach ($attributes as $attribute)
	        for ($i = 0; $i < count($localizedAttributesValuesAndNames); $i += 2)
    	        if ((int) $attribute['attribute_id'] == $localizedAttributesValuesAndNames[$i]->getAttributeId())
    	           array_push($localizedAttributes, array('id' => $localizedAttributesValuesAndNames[$i]->getAttributeId(), 'name' => $localizedAttributesValuesAndNames[$i]->getText(),
    	               'attribute_value_id' => (int) $attribute['value'], 'attribute_value_name' => $localizedAttributesValuesAndNames[$i + 1]->getText()));

	    // Serialize attributes into JSON map
	    return Encoder::encode($localizedAttributes, true);
    }
    
    /**
     * 
     * @param int $productId
     * @param array $attributes
     */
    private function getPrice($productId, $attributes)
    {
        $sessionFacade = new SessionFacade();
        
        // Get the base product price
    	$productPrice = $this->productPriceDao->get($sessionFacade->getStore()->getId(), $productId);
    	
    	$price = count($productPrice) == 0 ? 0 : $productPrice[0]->getValue();
    	
    	// Get the attributes prices
    	if (count($attributes) > 0) {
    	    $attributeValueIds = array();
    	    
    	    foreach ($attributes as $attribute)
    	        array_push($attributeValueIds, $attribute['value']);
    	    
    	    $attributesPrice = $this->attributeValuePriceDao->get($attributeValueIds, $sessionFacade->getStore()->getId());

    	    $price = $price + $attributesPrice[0][1];
    	}
    	
    	return $price;
    }
    
    /**
     * 
     * @param int $productId
     */
    private function getVat($productId)
    {
        $sessionFacade = new SessionFacade();
        
        // Get the product price
        $productPrice = $this->productPriceDao->get($sessionFacade->getStore()->getId(), $productId);
         
        return count($productPrice) == 0 ? null : $productPrice[0]->getVat();
    }
    
    /**
     * 
     * @param int $productId
     * @return string
     */
    private function getLocalizedProductName($productId)
    {
        $sessionFacade = new SessionFacade();
        
        $localizedProductTexts = $this->localizedProductTextDao->get($productId, $sessionFacade->getStore()->getLanguage());
        
        foreach ($localizedProductTexts as $localizedProductText)
            if ($localizedProductText->getType() == 'name')
                return $localizedProductText->getText();
            
        return null;
    }
    
    /**
     * 
     */
    private function getBasket()
    {
    	$sessionFacade = new SessionFacade();
    	
    	// Get the basket for the current session and store
    	$basket = $this->basketDao->get($sessionFacade->getSessionId(), $sessionFacade->getStore()->getId());

    	// Create basket if not found
    	if (count($basket) != 0)
    	    return $basket[0];
    	     
	    return $this->basketDao->insert($sessionFacade->getSessionId(), $sessionFacade->getStore()->getId(), 
	        0, 0, $sessionFacade->getStore()->getCurrency());
    }
    
}

?>